package com.wusuowei.shiro_jwt.aspect;


import cn.hutool.extra.servlet.ServletUtil;
import com.wusuowei.shiro_jwt.annotation.CrudLog;
import com.wusuowei.shiro_jwt.common.enums.BusinessType;
import com.wusuowei.shiro_jwt.mapper.SysLogMapper;
import com.wusuowei.shiro_jwt.model.po.Category;
import com.wusuowei.shiro_jwt.model.po.Product;
import com.wusuowei.shiro_jwt.model.po.SysLog;
import com.wusuowei.shiro_jwt.service.CategoryService;
import com.wusuowei.shiro_jwt.service.ProductService;
import com.wusuowei.shiro_jwt.utils.HttpContextUtil;
import com.wusuowei.shiro_jwt.utils.ServletUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Objects;

/**
 * @author yangyouwang
 * @title: SysLogAspect
 * @projectName crud
 * @description: 日志切面
 * @date 2021/4/18:37 AM
 */
@Aspect
@Component
@Slf4j
public class SysLogAspect {
    @Autowired
    private ProductService productService;
    @Autowired
    private CategoryService categoryService;

    @Resource
    private SysLogMapper sysLogMapper;

    /**
     * 切入点
     */
    @Pointcut(value = "@annotation(com.wusuowei.shiro_jwt.annotation.CrudLog)")
    public void logPointCut() {
        log.info("------>配置织入点");
    }
    @Before("logPointCut()")
    public void doBefore(JoinPoint joinPoint) {
        log.info("do before...");
    }
    /**
     * 方法返回后的通知
     */
    @AfterReturning(value = "logPointCut() && @annotation(crudLog)", returning = "obj")
    public void doAfterReturning(JoinPoint joinPoint, CrudLog crudLog, Object obj) throws UnknownHostException {
        // 处理完请求，返回内容
        log.info("doAfter save log ...");
        SysLog sysLog = handleOperLog(joinPoint, crudLog);
        sysLogMapper.insert(sysLog);

    }

    /**
     * 抛出异常后的通知
     */
    @AfterThrowing(value = "logPointCut() && @annotation(crudLog)", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, CrudLog crudLog, Exception e) throws UnknownHostException {
        SysLog sysLog = handleExceptionLog(joinPoint, crudLog, e);
        sysLogMapper.insert(sysLog);

    }

    /**
     * 错误操作日志
     */
    public SysLog handleExceptionLog(JoinPoint joinPoint, CrudLog crudLog, Exception e) throws UnknownHostException {
        SysLog sysLog = handleOperLog(joinPoint, crudLog);
        StringWriter stackTraceWriter = new StringWriter();
        //异常堆栈信息
        e.printStackTrace(new PrintWriter(stackTraceWriter, true));
        sysLog.setStackTrace(stackTraceWriter.toString());
        //错误信息
        String errMsg = e.getMessage();
        sysLog.setErrMsg(errMsg);
        //异常类型
        String exceptionName = e.toString();
        sysLog.setExceptionName(exceptionName);
        return sysLog;
    }

    /**
     * 操作日志
     */
    public SysLog handleOperLog(JoinPoint joinPoint, CrudLog crudLog) throws UnknownHostException {
        ServletRequestAttributes servletRequestAttributes =(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();

        String requestUrl = request.getRequestURL().toString();// 得到请求的资源
        String remoteAddr = request.getRemoteAddr();// 得到来访者的IP地址



        SysLog sysLog = new SysLog();
        //ip地址
//        String ip = HttpContextUtil.getIpAddress();
        String addr =InetAddress.getLocalHost().getHostAddress();
//        String ip = ServletUtil.getClientIP(((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest(), "");
        sysLog.setIpAddress(addr);
        //访问的url
        String url= String.valueOf(ServletUtils.getRequest());
        sysLog.setUrl(requestUrl);
        // 标题/业务类型
        // 获取 Product 对象并提取 proname
        if ("ProductController".equals(joinPoint.getTarget().getClass().getSimpleName())) {
            log.info("ProductController...");
            handleProductController(joinPoint, sysLog, crudLog);
        } else if ("CategoryController".equals(joinPoint.getTarget().getClass().getSimpleName())) {
            log.info("走了CategoryController...");
            handleCategoryController(joinPoint, sysLog, crudLog);
        } else {
            log.info("什么都没走");
            sysLog.setTitle(crudLog.title());
        }


//        sysLog.setTitle(crudLog.title());
        sysLog.setBusinessType(BusinessType.getMsg(crudLog.businessType()));
        // 类名称
        String className = joinPoint.getTarget().getClass().getSimpleName();
        sysLog.setClassName(className);
        //方法名称
        String methodName = joinPoint.getSignature().getName();
        sysLog.setMethodName(methodName);
        // 包名称
        String packageName = joinPoint.getSignature().getDeclaringTypeName();
        sysLog.setPackageName(packageName);
        // 参数值
        Object[] argsValue = Arrays.stream(joinPoint.getArgs()).toArray(Object[]::new);
        sysLog.setArgsValue(StringUtils.join(argsValue));
        // 参数名
        String[] argsNames = ((MethodSignature)joinPoint.getSignature()).getParameterNames();
        sysLog.setArgsName(StringUtils.join(argsNames));

        return sysLog;
    }
    public Product getProductFromArgs(Object[] args) {
        for (Object arg : args) {
            if (arg instanceof Product) {
                return (Product) arg;
            }
        }
        return null;
    }
    public Category getCategoryFromArgs(Object[] args) {
        for (Object arg : args) {
            if (arg instanceof Category) {
                return (Category) arg;
            }
        }
        return null;
    }
    public Integer getCategoryIdFromArgs(Object[] args) {
        for (Object arg : args) {
            if (arg instanceof Integer) {
                return (Integer) arg;  // 假设 ID 参数是 Integer 类型
            }
        }
        return null;
    }

    // Helper method to extract Product ID from arguments
    public Integer getProductIdFromArgs(Object[] args) {
        for (Object arg : args) {
            if (arg instanceof Integer) {
                return (Integer) arg;  // 假设 ID 参数是 Integer 类型
            }
        }
        return null;
    }
    public void handleProductController(JoinPoint joinPoint, SysLog sysLog, CrudLog crudLog) {
        String methodName = joinPoint.getSignature().getName();
        switch (methodName) {
            case "save":
            case "update":
                Product product = getProductFromArgs(joinPoint.getArgs());
                if (product != null) {
                    sysLog.setTitle(crudLog.title() + " : " + product.getProname());
                }
                break;
            case "delete":
                Integer productId = getProductIdFromArgs(joinPoint.getArgs());
                log.info("delete 中的productId:"+productId);
                if (productId != null) {
                     product = productService.getDeletedProductById(productId);
                     log.info("delete 中的product:"+product);
                    if (product != null) {
                        sysLog.setTitle(crudLog.title() + " - " + product.getProname());
                    }
                }
                break;
            default:
                sysLog.setTitle(crudLog.title());
                break;
        }
    }

    public void handleCategoryController(JoinPoint joinPoint, SysLog sysLog, CrudLog crudLog) {
        String methodName = joinPoint.getSignature().getName();
        switch (methodName) {
            case "save":
            case "update":
                Category category = getCategoryFromArgs(joinPoint.getArgs());
                if (category != null) {
                    sysLog.setTitle(crudLog.title() + " : " + category.getCname());
                }
                break;
            case "delete":
                Integer categoryId = getCategoryIdFromArgs(joinPoint.getArgs());
                if (categoryId != null) {
                     category = categoryService.getCategoryById(categoryId);
                    if (category != null) {
                        sysLog.setTitle(crudLog.title() + " - " + category.getCname());
                    }
                }
                break;
            default:
                sysLog.setTitle(crudLog.title());
                break;
        }
    }

}
